/* -*- mode: c++ -*- */
/**
 * @file   ShapeList.ih
 * @author Sebastien Fourey (GREYC)
 * @date   Sat Aug 18 2007
 *
 * @brief  Inline methods of the Transform classes.
 * \@copyright
 * This source code is part of the Board project, a C++ library whose
 * purpose is to allow simple drawings in EPS, FIG or SVG files.
 * Copyright (C) 2007 Sebastien Fourey <http://foureys.users.greyc.fr/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#if defined( max )
#undef max
#define _HAS_MSVC_MAX_ true
#endif

ShapeList::ShapeList( int depth )
  : Shape( Color::Null, Color::Null, 1.0, SolidStyle, ButtCap, MiterJoin, depth ),
    _nextDepth( std::numeric_limits<int>::max() - 1 )
{ }

template<typename T>
T &
ShapeList::last( const std::size_t position )
{
  if ( position < _shapes.size() ) {
    std::vector<Shape*>::reverse_iterator it = _shapes.rbegin() + position;
    Shape * pshape = *it;
    T * result = dynamic_cast<T*>( pshape );
    if ( !result ) {
      std::cerr << "Error: ShapeList::last<> called with invalid result type\n";
      exit(-1);
    }
    return dynamic_cast<T&>( *result );
  } else {
    Tools::error << "Trying to access an element that does not exist ("
                 << position << "/" << _shapes.size() << ").\n";
    throw -1;
  }
}

template<typename T>
T & ShapeList::topLevelFindLast( std::size_t position )
{
  std::vector<Shape*>::reverse_iterator it = _shapes.rbegin();
  while ( it != _shapes.rend() ) {
    T * shape = dynamic_cast<T*>(*it);
    if ( shape ) {
      if ( ! position ) {
        return *shape;
      } else {
        --position;
      }
    }
    ++it;
  }
  throw Exception("topLevelFindLast<T>(): no such shape type found (" + std::string(typeid(T).name()) + ")");
}

ShapeList::TopLevelIterator::TopLevelIterator(std::vector<Shape*>::iterator it)
  :_it(it)
{
}

Shape & ShapeList::TopLevelIterator::operator*()
{
  return **_it;
}

Shape * ShapeList::TopLevelIterator::pointer()
{
  return *_it;
}

ShapeList::TopLevelIterator & ShapeList::TopLevelIterator::operator++()
{
  ++_it;
  return *this;
}

ShapeList::TopLevelIterator ShapeList::TopLevelIterator::operator++(int)
{
  TopLevelIterator previous(*this);
  ++_it;
  return previous;
}

bool ShapeList::TopLevelIterator::operator==(const TopLevelIterator & other)
{
  return _it == other._it;
}

bool ShapeList::TopLevelIterator::operator!=(const TopLevelIterator & other)
{
  return _it != other._it;
}

ShapeList::TopLevelConstIterator::TopLevelConstIterator(std::vector<Shape*>::const_iterator it)
  :_it(it)
{
}

const Shape & ShapeList::TopLevelConstIterator::operator*()
{
  return **_it;
}

const Shape * ShapeList::TopLevelConstIterator::pointer()
{
  return *_it;
}

ShapeList::TopLevelConstIterator & ShapeList::TopLevelConstIterator::operator++()
{
  ++_it;
  return *this;
}

ShapeList::TopLevelConstIterator ShapeList::TopLevelConstIterator::operator++(int)
{
  TopLevelConstIterator previous(*this);
  ++_it;
  return previous;
}

bool ShapeList::TopLevelConstIterator::operator==(const TopLevelConstIterator & other)
{
  return _it == other._it;
}

bool ShapeList::TopLevelConstIterator::operator!=(const TopLevelConstIterator & other)
{
  return _it != other._it;
}

ShapeList::TopLevelIterator ShapeList::begin()
{
  return TopLevelIterator(_shapes.begin());
}

ShapeList::TopLevelIterator ShapeList::end()
{
  return TopLevelIterator(_shapes.end());
}

ShapeList::TopLevelConstIterator ShapeList::begin() const
{
  return TopLevelConstIterator(_shapes.begin());
}

ShapeList::TopLevelConstIterator ShapeList::cbegin() const
{
  return TopLevelConstIterator(_shapes.begin());
}

ShapeList::TopLevelConstIterator ShapeList::end() const
{
  return TopLevelConstIterator(_shapes.end());
}

ShapeList::TopLevelConstIterator ShapeList::cend() const
{
  return TopLevelConstIterator(_shapes.end());
}

ShapeList::DepthFirstIterator ShapeList::depthFirstBegin()
{
  return DepthFirstIterator(this);
}

ShapeList::DepthFirstIterator ShapeList::depthFirstEnd()
{
  return DepthFirstIterator();
}

ShapeList::BreadthFirstIterator ShapeList::breadthFirstBegin()
{
  return BreadthFirstIterator(this);
}

ShapeList::BreadthFirstIterator ShapeList::breadthFirstEnd()
{
  return BreadthFirstIterator();
}

std::size_t ShapeList::size() const
{
  return _shapes.size();
}

ShapeList::DepthFirstIterator::DepthFirstIterator()
{
}

ShapeList::DepthFirstIterator::DepthFirstIterator(ShapeList * list)
{
  _shapeListsStack.push(list);
  _iteratorsStack.push(list->begin());
  moveToFirstActuelShape();
}

Shape & ShapeList::DepthFirstIterator::operator*() {
  return *(_iteratorsStack.top());
}

Shape * ShapeList::DepthFirstIterator::pointer() {
  return _iteratorsStack.top().pointer();
}

bool ShapeList::DepthFirstIterator::operator==(const DepthFirstIterator & other)
{
  return (_shapeListsStack.empty() && other._shapeListsStack.empty())
      || ( (!_shapeListsStack.empty() && !other._shapeListsStack.empty())
           && (_shapeListsStack.top() == other._shapeListsStack.top())
           && (_iteratorsStack.top() == other._iteratorsStack.top()));
}

bool ShapeList::DepthFirstIterator::operator!=(const DepthFirstIterator & other)
{
  return !(*this == other);
}

ShapeList::DepthFirstIterator & ShapeList::DepthFirstIterator::operator++() {
  moveToNextActualShape();
  return *this;
}

ShapeList::DepthFirstIterator ShapeList::DepthFirstIterator::operator++(int) {
  DepthFirstIterator currentValue(*this);
  moveToNextActualShape();
  return currentValue;
}

ShapeList::BreadthFirstIterator::BreadthFirstIterator()
{
}

ShapeList::BreadthFirstIterator::BreadthFirstIterator(ShapeList * list)
{
  _shapeListsQueue.push(list);
  _iteratorsQueue.push(list->begin());
  moveToFirstActuelShape();
}

Shape & ShapeList::BreadthFirstIterator::operator*()
{
  return *(_iteratorsQueue.front());
}

Shape * ShapeList::BreadthFirstIterator::pointer()
{
  return _iteratorsQueue.front().pointer();
}

bool ShapeList::BreadthFirstIterator::operator==(const BreadthFirstIterator & other)
{
  return (_shapeListsQueue.empty() && other._shapeListsQueue.empty())
      || ( (!_shapeListsQueue.empty() && !other._shapeListsQueue.empty())
           && (_shapeListsQueue.front() == other._shapeListsQueue.front())
           && (_iteratorsQueue.front() == other._iteratorsQueue.front()));
}

bool ShapeList::BreadthFirstIterator::operator!=(const BreadthFirstIterator & other)
{
  return !(*this == other);
}

ShapeList::BreadthFirstIterator & ShapeList::BreadthFirstIterator::operator++()
{
  moveToNextActualShape();
  return *this;
}

ShapeList::BreadthFirstIterator ShapeList::BreadthFirstIterator::operator++(int)
{
  BreadthFirstIterator currentValue(*this);
  moveToNextActualShape();
  return currentValue;
}

#if defined( _HAS_MSVC_MAX_ )
#define max(A,B) ((A)>(B)?(A):(B))
#endif
